/**
 * @description: 初始化实例属性，保存参数
 * @param {String} name // ws名称
 * @param {String} url // ws地址
 * @param {Number} timeout // 心跳频率，默认20秒
 * @param {Number} delayTimeout // 延迟重连时间，默认5秒
 * @param {String} pingInfo // 发送给服务器的心跳信息
 * @param {String} pingInfoRes // 服务器返回的心跳信息
 * @param {Function} received // 监听服务器返回信息
 *
 * url:
 * http对应ws
 * https对应wss
 * 其他组件使用
 * initWebSocket() {
 *  if (!token) return;
 *   let wsurl = 'ws://localhost:80'; // ws地址
 *   // 初始化
 *   this.ws = new Socket({
 *    url: wsurl,
 *    pingInfo: `{"type":"9001"}`, // 给服务器的心跳信息，默认Are you still alive
 *    received: (data) => {
 *     // 监听服务器返回信息
 *     this.websocketOnMessage(data);
 *    },
 *  });
 * },
 * websocketOnMessage(data) {
 *  console.log(data);
 * }
 */

export class Socket {
    constructor({
        url,
        received,
        name = "default",
        pingInfo = "Are you still alive",
        pingInfoRes = "Yes,I still alive",
        timeout = 1000 * 60,
    }) {
        this.url = url;
        this.callback = received;
        this.name = name;
        this.ws = null;
        this.pingInfo = pingInfo;
        this.pingInfoRes = pingInfoRes;
        this.pingSetTimeout = null;
        this.serverTimeoutObj = null;
        // 心跳检测频率
        this._timeout = timeout;
        // 重连延迟避免请求过多
        this.connectTimeout = null;
        this.isReconnection = false;
        this.delayTimeout = 5000;
        this.connect();
    }
    connect(data) {
        if (!this.url) {
            console.error("WebSocket地址不能为空！");
            return;
        }
        this.ws = new WebSocket(this.url);
        // 建立连接
        this.ws.onopen = (e) => {
            console.log(`${this.name}-WS连接成功`, e);
            this._onopen(data);
        };
        // 接受服务器返回的信息
        this.ws.onmessage = (e) => {
            // 收到服务器信息，心跳重置
            this._resetHeart();

            if (typeof this.callback === "function") {
                // 如果不是心跳信息
                if (e.data !== this.pingInfoRes) {
                    return this.callback(JSON.parse(e.data));
                }
            } else {
                console.error(`${this.name}-received参数的类型必须为函数`);
            }
        };
        // 关闭连接
        this.ws.onclose = (e) => {
            console.log(`${this.name}-WS连接关闭`, e);
        };
        // 报错
        this.ws.onerror = (e) => {
            console.log(`${this.name}-WS连接报错`, e);
            this._reconnect(e);
        };
    }
    _onopen(data) {
        // 心跳开启
        this._heartCheck();
        // 初始化给后台发送数据
        // if (data !== undefined) {
        return this.ws.send(JSON.stringify({ "type": "9001" }));
        // }
    }
    sendMsg(data) {
        let msg = JSON.stringify(data);
        return this.ws.send(msg);
    }
    _resetHeart() {
        this._resetSetTimeout("pingSetTimeout");
        this._resetSetTimeout("serverTimeoutObj");
        this._resetSetTimeout("connectTimeout");
        this._heartCheck();
        return this;
    }
    _resetSetTimeout(key) {
        this[key] && clearTimeout(this[key]);
    }
    // 重连
    _reconnect() {
        const self = this;
        if (this.isReconnection) return;
        console.log(`${this.name}-WS重连中...`);
        this.isReconnection = true;
        // 没连接上会一直重连，设置延迟避免请求过多
        this._resetSetTimeout("pingSetTimeout");
        this._resetSetTimeout("serverTimeoutObj");
        this._resetSetTimeout("connectTimeout");
        this.connectTimeout = setTimeout(() => {
            // 新连接
            self.ws.close();
            self.ws = null;
            self.connect();
            self.isReconnection = false;
        }, self.delayTimeout);
    }
    // 心跳
    _heartCheck() {
        const self = this;
        this._resetSetTimeout("pingSetTimeout");
        this._resetSetTimeout("serverTimeoutObj");
        this.pingSetTimeout = setTimeout(() => {
            // 这里发送一个心跳，后端收到后，返回一个心跳消息，
            if (self.ws.readyState === 1) {
                self.ws.send(`{"type":"9000"}`);
                // self.ws.send(JSON.stringify(self.pingInfo));
                self.serverTimeoutObj = setTimeout(() => {
                    console.log(`${self.name}-WS未收到服务心跳信息，重连`);
                    self._reconnect();
                }, self._timeout);
            } else {
                console.log(`${self.name}-WS状态不正常，重连`);
                // 链接状态不正常重连
                self._reconnect();
            }
        }, self._timeout);
    }
    close() {
        this.ws.close();
        this.ws = null;
        this._resetSetTimeout("pingSetTimeout");
        this._resetSetTimeout("serverTimeoutObj");
        this._resetSetTimeout("connectTimeout");
        console.log(`${this.name}-WS手动关闭了`);
    }
}
